﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data;
using System.Security.Cryptography;
using System.IO;
using System.Text;
using TCL.EO;
using TCL.DB;
using System.Web.Security;

namespace TCL.FUNC
{
    public class SecurityEx
    {
        public static Boolean CheckPermission(Int16 iFuncType)
        {
            //if (e.iType != ConstEx.funcButtonToolBar.BACK_LIST && (new ShareDAO.UserDAO()).SelectBy_sPermission(Session["secret"], Convert.ToString(Request.Url.AbsolutePath), e.iType) == false)
            //{
            //    MsgUC1.setNotifications(ConstEx.FunctionSetMsg.DANGER, MessagesEx.Khong_Co_Quyen_Truy_Cap, null);
            //    Commons.setAccessDenied(Page, null);
            //    return;
            //}
            return true;
        }

        public static String getUsername(Boolean isAccessDenial)
        {
            String sUsername = ShareDAO.UserDAO.getPK_iAccountID(Convert.ToString(System.Web.HttpContext.Current.Session["secret"])).Name;
            if (isAccessDenial)
                (new Logs()).WriteLog_To_DB(new LogEO(String.Format(MessagesEx.ATTACH_TWO_INFO, sUsername, OtherEx.getInfoRequest(2)), ConstEx.Log_iType.ACCOUNT_ACCESS_DENIAL), false);
            return sUsername;
        }

        public class Token
        {
            /// <summary>
            /// 
            /// </summary>
            /// <param name="iType">
            /// iType = 1: Reset mật khẩu
            /// iType = 2: Hủy đăng ký nhận bài viết mới thành công
            /// iType = 3: Hủy đăng ký khi có bình luận mới thành công
            /// iType = 4: Khác
            /// iType = 9: Test
            /// </param>
            /// <param name="para1"></param>
            /// <param name="para2"></param>
            /// <param name="para3"></param>
            /// <returns></returns>
            public static string getToken(TokenEO _TokenEO)
            {
                return HttpUtility.UrlEncode(SecurityEx.Login.Encrypt(ConvertEx.JsonEx.Object_2_Json(_TokenEO), SystemEx.getAppSettings("FACEBOOK")), System.Text.UTF8Encoding.Default);
            }

            public static TokenEO checkToken(String strToken)
            {
                TokenEO objToken = new TokenEO(0, DateTime.MinValue);
                try
                {
                    strToken = HttpUtility.UrlDecode(strToken, System.Text.UTF8Encoding.Default).Replace(" ", "+");
                    objToken = ConvertEx.JsonEx.Json_2_Object<TokenEO>(SecurityEx.Login.Decrypt(strToken, SystemEx.getAppSettings("FACEBOOK")), objToken.GetType());
                    if (objToken != null)
                    {
                        objToken.bStatus = false;
                        objToken.sError = "";
                        if (objToken.tExpires < DateTime.Now)
                        {
                            objToken.sError = "Token đã hết hạn.";
                            return objToken;
                        }
                        switch (objToken.iType)
                        {
                            case ConstEx.Token_iType_C.ResetPassword:
                                objToken.bStatus = true;
                                break;

                            case ConstEx.Token_iType_C.UnRegNewLetter:
                                objToken.bStatus = true;
                                break;

                            case ConstEx.Token_iType_C.UnNotificationQA:
                                //QuestionAnswerEO _QuestionAnswerEO = new QuestionAnswerEO();
                                //_QuestionAnswerEO = (QuestionAnswerEO)JsonEx.Json2Object(Convert.ToString(objToken.objSender), _QuestionAnswerEO.GetType());
                                //if ((new QuestionAnswerDAO()).Update_bNotification_Or_iLike(_QuestionAnswerEO))
                                //    objToken.bStatus = true;
                                break;

                            case ConstEx.Token_iType_C.VerifyAccount:
                                break;

                            case ConstEx.Token_iType_C.Test:
                                if (StringEx.Equals(objToken.objSender, StringEx.Trim(SystemEx.getAppSettings("UserTest"))))
                                    objToken.bStatus = true;
                                break;

                            default:
                                objToken.sError = "Loại token [" + objToken.iType + "] này không có trong hệ thống.";
                                break;
                        }
                        return objToken;
                    }
                    else
                        throw new System.ArgumentException("Token không hợp lệ.", "original");
                    return null;
                }
                catch (Exception ex)
                {
                    objToken.sError = ex.Message;
                    return objToken;
                }
            }
        }

        public class Login
        {
            public static string Encrypt(string clearText, string EncryptionKey)
            {
                //string EncryptionKey = "MAKV2SPBNI99212";
                byte[] clearBytes = Encoding.Unicode.GetBytes(clearText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateEncryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(clearBytes, 0, clearBytes.Length);
                            cs.Close();
                        }
                        clearText = Convert.ToBase64String(ms.ToArray());
                    }
                }
                return clearText;
            }

            public static string Decrypt(string cipherText, string EncryptionKey)
            {
                //string EncryptionKey = "MAKV2SPBNI99212";
                byte[] cipherBytes = Convert.FromBase64String(cipherText);
                using (Aes encryptor = Aes.Create())
                {
                    Rfc2898DeriveBytes pdb = new Rfc2898DeriveBytes(EncryptionKey, new byte[] { 0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76 });
                    encryptor.Key = pdb.GetBytes(32);
                    encryptor.IV = pdb.GetBytes(16);
                    using (MemoryStream ms = new MemoryStream())
                    {
                        using (CryptoStream cs = new CryptoStream(ms, encryptor.CreateDecryptor(), CryptoStreamMode.Write))
                        {
                            cs.Write(cipherBytes, 0, cipherBytes.Length);
                            cs.Close();
                        }
                        cipherText = Encoding.Unicode.GetString(ms.ToArray());
                    }
                }
                return cipherText;
            }
        }

        /// <summary>
        /// EnCrypt (Mã hóa chuỗi theo thuật toán SHA1)
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public static string EnCrypt(String sInput, String sSalt = "QsXpL,%^&")
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(EncryptString(StringEx.Trim(sInput), sSalt), "SHA1").ToLower();
        }

        public static string RandomPassword()
        {
            string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
            string res = "";
            Random rnd = new Random();
            for (int i = 0; i < 16; i++)
            {
                res += valid[rnd.Next(valid.Length)];
            }
            string randpass = res;
            return randpass;
        }

        /// <summary>
        /// Hàm mã hóa và giải mã
        /// </summary>
        /// <param name="type">true: mã hóa;    false: giải mã</param>
        /// <param name="input">chuỗi đầu vào</param>
        /// <returns>chuỗi đầu ra</returns>
        public static string Encrypt_Decrypt(bool type, string input)
        {
            //HttpUtility.UrlEncode(str)
            char[] map1 = new char[] { ' ', '!', '\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', ';', '<', '=', '>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '{', '|', '}', '~' };

            char[] map2 = new char[] { 'U', 'a', '^', 'b', '~', 'c', ',', 'h', 'j', '#', 'k', 'T', 'Y', '\\', 'P', 'Q', '+', 'R', '}', 'w', '=', 'm', ']', 'F', '"', 'L', 'X', '[', '<', '.', '>', '`', '8', ':', 'O', 'f', '%', 'B', 'C', '(', 'z', 'S', 'x', '{', 'M', 'i', '0', '!', '5', '6', 'd', 'I', 'r', '\'', '1', '2', 'p', ';', 'N', '_', 'G', 'e', '/', 'g', 'q', '9', '3', 'H', '4', 'v', '@', 'V', '?', 'W', 'J', '|', 'K', ' ', 'A', 'n', ')', 'o', 'Z', '&', 's', 't', 'y', '7', 'l', '$', 'u', '-', 'D', 'E', '*' };




            //char[] map2 = new char[] {UabchjkTYPQRwmFLXHi8OfBCzSxM056dIr12pNGegq934vVWJKAnoZsty7luDE};

            //khởi tạo
            //string src_chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
            //string des_chars = "UabchjkTYPQRwmFLXHi8OfBCzSxM056dIr12pNGegq934vVWJKAnoZsty7luDE";
            string output = "";
            //char[] src_array = new char[62];
            //char[] des_array = new char[62];

            //type=true là mã hóa
            if (type == true)
            {
                //kiểm tra trong mảng map rồi lấy ra ký tự tương ứng
                char[] charArr = input.ToCharArray();
                foreach (char ch in charArr)
                {
                    int index = Array.IndexOf(map1, ch);
                    output = output + map2[index].ToString();
                }
                return output;
            }

            //type=false là giải mã
            else
            {
                //kiểm tra trong mảng map rồi lấy ra ký tự tương ứng
                char[] charArr = input.ToCharArray();
                foreach (char ch in charArr)
                {
                    int index = Array.IndexOf(map2, ch);
                    output = output + map1[index].ToString();
                }
                return output;
            }

            //kiểm tra trong mảng map rồi lấy ra ký tự tương ứng
            //char[] charArr = input.ToCharArray();
            //foreach (char ch in charArr)
            //{
            //    int index = Array.IndexOf(src_array, ch);
            //    output = output + des_array[index].ToString();
            //}
            //return output;
        }

        /// <summary>
        /// timeout+username+access+password+id
        /// </summary>
        /// <param name="timeout">cookie timeout (ddMMyyyy)</param>
        /// <param name="username">username</param>
        /// <param name="access">access</param>
        /// <param name="password">password</param>
        /// <param name="id">id</param>
        /// <returns></returns>
        public static string AuthenticationLogin_Encrypt(DateTime timeout, string username, string access, string state, string password, string id)
        {
            string strOutput = "";
            //B1 Mã hóa bằng SHA1
            strOutput = SecurityEx.EnCrypt(username + access + state + password);
            //B2 Mã hóa bằng Base64
            strOutput = EncryptString(timeout.ToString("ddMMyyyyhhmmss") + strOutput + id, "Th@ngNM11");
            //B3 Mã hóa bằng ASCII
            strOutput = Encrypt_Decrypt(true, strOutput);
            return strOutput;
        }

        public static string AuthenticationLogin_Decrypt(string strCookie)
        {
            string strOutput = "";
            //B1 Giải mã bằng ASCII
            strOutput = Encrypt_Decrypt(false, strCookie);
            //B2 Giải mã bằng Base64
            strOutput = DecryptString(strOutput, "Th@ngNM11");
            //B3 Trả về
            return strOutput;
        }

        public static string EncryptString(string Message, string Passphrase)
        {

            byte[] Results;

            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Buoc 1: Bam chuoi su dung MD5

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();

            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));

            // Step 2. Tao doi tuong TripleDESCryptoServiceProvider moi

            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Cai dat bo ma hoa

            TDESAlgorithm.Key = TDESKey;

            TDESAlgorithm.Mode = CipherMode.ECB;

            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert chuoi (Message) thanh dang byte[]

            byte[] DataToEncrypt = UTF8.GetBytes(Message);

            // Step 5. Ma hoa chuoi

            try
            {

                ICryptoTransform Encryptor = TDESAlgorithm.CreateEncryptor();

                Results = Encryptor.TransformFinalBlock(DataToEncrypt, 0, DataToEncrypt.Length);

            }

            finally
            {

                // Xoa moi thong tin ve Triple DES va HashProvider de dam bao an toan

                TDESAlgorithm.Clear();

                HashProvider.Clear();

            }

            // Step 6. Tra ve chuoi da ma hoa bang thuat toan Base64

            return Convert.ToBase64String(Results);

        }

        //Hàm gi?i mă chu?i

        public static string DecryptString(string Message, string Passphrase)
        {

            byte[] Results;

            System.Text.UTF8Encoding UTF8 = new System.Text.UTF8Encoding();

            // Step 1. Bam chuoi su dung MD5

            MD5CryptoServiceProvider HashProvider = new MD5CryptoServiceProvider();

            byte[] TDESKey = HashProvider.ComputeHash(UTF8.GetBytes(Passphrase));

            // Step 2. Tao doi tuong TripleDESCryptoServiceProvider moi

            TripleDESCryptoServiceProvider TDESAlgorithm = new TripleDESCryptoServiceProvider();

            // Step 3. Cai dat bo giai ma

            TDESAlgorithm.Key = TDESKey;

            TDESAlgorithm.Mode = CipherMode.ECB;

            TDESAlgorithm.Padding = PaddingMode.PKCS7;

            // Step 4. Convert chuoi (Message) thanh dang byte[]

            byte[] DataToDecrypt = Convert.FromBase64String(Message);

            // Step 5. Bat dau giai ma chuoi

            try
            {

                ICryptoTransform Decryptor = TDESAlgorithm.CreateDecryptor();

                Results = Decryptor.TransformFinalBlock(DataToDecrypt, 0, DataToDecrypt.Length);

            }

            finally
            {

                // Xoa moi thong tin ve Triple DES va HashProvider de dam bao an toan

                TDESAlgorithm.Clear();

                HashProvider.Clear();

            }

            // Step 6. Tra ve ket qua bang dinh dang UTF8

            return UTF8.GetString(Results);

        }

        public static string Base64Encode(string plainText)
        {
            var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
            return System.Convert.ToBase64String(plainTextBytes);
        }

        public static string Base64Decode(string base64EncodedData)
        {
            var base64EncodedBytes = System.Convert.FromBase64String(base64EncodedData);
            return System.Text.Encoding.UTF8.GetString(base64EncodedBytes);
        }

        public static string SHA1_Encrypt(string input)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(input, System.Web.Configuration.FormsAuthPasswordFormat.SHA1.ToString()).ToLower();
        }

        public static string MD5_Encrypt(string input)
        {
            return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(input, System.Web.Configuration.FormsAuthPasswordFormat.MD5.ToString()).ToLower();
        }








        /// <summary>
        /// Step 1: strInput
        /// Step 2: Salt = MD5(Base64(strInput))
        /// Step 3: strInput = SHA1(strInput, Salt)
        /// Step 4: 
        /// </summary>
        /// <param name="strInput"></param>
        /// <returns></returns>
        public static String Certificate_Authority(String strInput)
        {
            String strEncrypt = Login.Encrypt(strInput, MD5_Encrypt(Base64Encode(strInput)));
            return strEncrypt;
        }

        public static String Insert_Salt(String strInput, String strSalt)
        {
            Int32 index = strInput.Length % 9;
            return strInput.Insert(index, strSalt);
        }

        public String Check_Access(Int16 iSubFunc)
        {
            try
            {
                if (HttpContext.Current.Request.QueryString["r"] != null)
                {
                    String sFuncID = SecurityEx.Login.Decrypt(HttpContext.Current.Request.QueryString["r"], SystemEx.getAppSettings("PRIVATE_KEY"));
                    sFuncID = sFuncID + Convert.ToString(iSubFunc);
                    Int32 iFuncID = 0;
                    if (Int32.TryParse(sFuncID, out iFuncID))
                    {
                        FuncEO objFunc = (new ShareDAO.FuncDAO()).SelectItem(iFuncID);
                        if (!CheckEx.IsObject(objFunc))
                            return String.Format("Chức năng [{0}] không tồn tại.", iFuncID);
                        else if (objFunc.bStatus == false)
                            return String.Format("Chức năng [{0}] đã bị khóa.", iFuncID);
                        else
                        {
                            if (!StringEx.Equals(objFunc.sToken, SecurityEx.Login.Encrypt(objFunc.sPath, objFunc.PK_iFunctionID.ToString() + objFunc.iRole.ToString())))
                                return String.Format("Chức năng [{0}] đã bị sửa đổi.", iFuncID);
                            String sSession = SecurityEx.Login.Decrypt(Convert.ToString(HttpContext.Current.Session["secret"]), SecurityEx.Base64Encode(System.Web.HttpContext.Current.Request.ServerVariables["remote_addr"]));
                            FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(sSession);
                            if (ticket != null)
                            {
                                List<String> lstFunc = StringEx.Split(ticket.UserData, ',');
                                if ((lstFunc.Count > 0) && (lstFunc.Exists(n => StringEx.Equals(n, objFunc.PK_iFunctionID.ToString()))))
                                {
                                    return String.Empty;
                                }
                                else
                                    return String.Format("User [{0}] chưa phân quyền, chưa được phân quyền cho chức năng này.", ticket.Version);
                            }
                            else
                                return String.Format("User không tồn tại.", iFuncID);
                        }
                    }
                    else
                        return String.Format("Dữ liệu nhập vào [{0}] không đúng định dạng số.", sFuncID);
                }
                return String.Format("Sai đường dẫn chức năng.");
            }
            catch (Exception ex)
            {
                return ex.ToString();
            }
        }

        public static Boolean WebServices_CheckTokenKey(String sToken)
        {
            if (StringEx.Equals(sToken, MD5_Encrypt(OtherEx.getInfoRequest(2) + Folder_File.getFileNameByDateTime(ConstEx.Log_iType_NameFile_DateTime_C.Day, "") + "NmT@99!((@")))
                return true;
            else
                return false;
        }

        public static String getTokenFunc(FuncEO objInput, Boolean isValid = true, String _sToken = "")
        {
            String sRet = SHA1_Encrypt(objInput.iRole.ToString() + objInput.sName + objInput.bStatus.ToString() + objInput.iAppID.ToString() + objInput.sPath + objInput.iParentID.ToString());
            if (isValid && !String.IsNullOrEmpty(_sToken))
            {
                if (!StringEx.Equals(sRet, _sToken))
                    return "Error: Chức năng đã bị thay đổi.";
                else
                    return String.Empty;
            }
            return sRet;
        }

        public static String getKey(Int16 iType)
        {
            try
            {
                String strRetKey = "";
                Random rd1 = new Random();
                Random rd2 = new Random();
                String[] arrMap = "KBZe4aH6lAWfNOiQRSTo7JrYCuwy8cd2MghPEkbmnUpqX3tjvxGz0D1Fs5IVL9".Select(x => x.ToString()).ToArray();
                Int32 iTemp = 0;
                String sTemp = DateTime.Now.ToString("ddyyHHmmMMddss");
                if (sTemp.Length == 14)
                {
                    for (int i = 0; i < 14; i += 2)
                    {
                        Int32.TryParse(sTemp.Substring(i, 2), out iTemp);
                        strRetKey += arrMap[iTemp];
                    }
                }
                return Convert.ToString(iType) + strRetKey;
            }
            catch (Exception ex)
            {
                return "000000000";
            }
        }
    }
}